package com.ruoyi.web.bankCard;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ruoyi.business.appuser.config.WxpayConfigConfig;
import com.ruoyi.business.domain.ShopCardnum;
import com.ruoyi.business.domain.ShopOrder;
import com.ruoyi.business.service.impl.ShopCardnumServiceImpl;
import com.ruoyi.business.service.impl.ShopOrderServiceImpl;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.service.impl.SysUserServiceImpl;
import com.ruoyi.web.asyserver.AsyncService;
import com.ruoyi.web.domain.WxpayResponse;
import com.ruoyi.web.utils.CommonUtil;
import com.ruoyi.web.utils.SmsUtil;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders;
import com.wechat.pay.contrib.apache.httpclient.exception.ParseException;
import com.wechat.pay.contrib.apache.httpclient.exception.ValidationException;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;


@RestController
@Slf4j
@RequestMapping("/wxpay")
public class WxPayV3Controller {


    @Value("${wxpay.appid}")
    private String appId;
    @Value("${wxpay.appSecret}")
    private String appSecret;
    @Value("${wxpay.mchSerialNo}")
    private String mchSerialNo;
    @Value("${wxpay.apiKey3}")
    private String apiKey3;
    @Value("${wxpay.keyPath}")
    private String keyPath;
    @Value("${wxpay.domain}")
    private String domain;
    @Value("${wxpay.certPath}")
    private String certPath;
    @Value("${wxpay.mchId}")
    private String mchId;

    @Autowired
    private SysUserServiceImpl sysUserService;

    @Autowired
    private AsyncService asyncService;

    @Autowired
    private ShopOrderServiceImpl orderService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ShopCardnumServiceImpl cardnumService;



    private final WxpayConfigConfig wxpayConfigService;


    @Autowired
    public WxPayV3Controller(WxpayConfigConfig wxpayConfigService) {
        // 注入 WxpayConfigService
        this.wxpayConfigService = wxpayConfigService;
    }

    @PostMapping("/check")
    public AjaxResult check(@RequestBody WxpayResponse wxpayResponse) throws Exception {

        //校验验证码
        if (redisTemplate.hasKey("user_phone_" + wxpayResponse.getPhonenumber())) {
            String code = redisTemplate.opsForValue().get("user_phone_" + wxpayResponse.getPhonenumber()).toString();
            if (!code.equals(wxpayResponse.getSmsCode())) {
                return AjaxResult.error("验证码已过期");
            }
        }
        //校验用户是否领取过
        SysUser sysUser = sysUserService.selectUserById(SecurityUtils.getUserId());
        //校验用户code是否过期
        if (redisTemplate.hasKey(sysUser.getUserValue())) {
            sysUser.setPhonenumber(wxpayResponse.getPhonenumber());
            sysUserService.updateById(sysUser);
        } else {
            return AjaxResult.error("身份验证已过期,请重新联系工作人员扫码");
        }

        //校验是否存在已支付的订单
        SysUser user1 = sysUserService.checkUser(sysUser.getOpenid());
        if(user1!=null){
            return AjaxResult.error("您已经领取过奖券,请勿重复领取");
        }


        //扣库存
        try {
            boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent("card_num_lock", "locked");
            if (lockAcquired) {
                redisTemplate.expire("card_num_lock", 3, TimeUnit.SECONDS);
            } else {
                throw new RuntimeException("请求频繁请稍后再试");
            }
            if(!redisTemplate.hasKey("card_num")){
                //获取本月批次数量
                ShopCardnum shopCardnum = cardnumService.getOne(new QueryWrapper<ShopCardnum>().lambda()
                        .eq(ShopCardnum::getMonth, DateUtil.format(new Date(), "yyyy-MM"))
                        .eq(ShopCardnum::getDelFlag, 0).last("limit 1"));
                //库存不足发送短信提醒工作人员
                if(shopCardnum.getNum()<100){
                    if (!redisTemplate.hasKey("sendRemind")){
                        redisTemplate.opsForValue().set("sendRemind","",2,TimeUnit.HOURS);
                        SmsUtil.sendRemind();
                    }
                }
                // 当前时间
                long now = System.currentTimeMillis();

                // 本月月底时间
                long endOfMonth = DateUtil.endOfMonth(DateUtil.date()).getTime();

                // 计算相差秒数
                long seconds = (endOfMonth - now) / 1000;
                log.info("首次获取card_num ===>{}",shopCardnum.getNum());
                redisTemplate.opsForValue().set("card_num",shopCardnum.getNum(),seconds,TimeUnit.SECONDS);
            }

            int num = (int)redisTemplate.opsForValue().get("card_num");
            if(num-1>=0){
                redisTemplate.opsForValue().decrement("card_num");
                log.info("扣减card_num库存 ===>{}",(int)redisTemplate.opsForValue().get("card_num"));
            }
            //减完库存,删除锁
            redisTemplate.delete("card_num_lock");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            redisTemplate.delete("card_num_lock");
        }

        //创建订单并且锁定库存
        ShopOrder shopOrder = new ShopOrder();
        shopOrder.setCreateTime(new Date());
        shopOrder.setOrderStatus(0l);
        shopOrder.setPayStatus(0l);
        shopOrder.setDelFlag("0");
        shopOrder.setUserId(SecurityUtils.getUserId());
        shopOrder.setApplyId(sysUser.getApplyId());
        shopOrder.setOpenid(sysUser.getOpenid());
        shopOrder.setPayType("1");
        orderService.save(shopOrder);
        //存储订单信息
        redisTemplate.opsForValue().set("order_id_"+sysUser.getOpenid(),shopOrder.getOrderId(),2,TimeUnit.HOURS);

        return AjaxResult.success();


    }


    /**
     * 微信jaspi/支付宝H5支付  臻享贵宾厅服务
     *
     * @return
     * @throws Exception
     */
    @RequestMapping("/jsApiPay")
    @RepeatSubmit
    public String jsApiPay(@RequestBody WxpayResponse wxpayResponse) throws Exception {
        log.info("-----------------------------开始支付-------------------------------");
        SysUser sysUser = sysUserService.getById(SecurityUtils.getUserId());
        if (redisTemplate.hasKey("order_id_"+sysUser.getOpenid())) {
            wxpayResponse.setOrderId((long) redisTemplate.opsForValue().get("order_id_" + sysUser.getOpenid()));
            wxpayResponse.setOpenid(sysUser.getOpenid());
        } else {
            throw new RuntimeException("订单已过期");
        }

        log.info("传参=========>{}", wxpayResponse);
        //将用户订单存储到redis中
        return wxPay(wxpayResponse);


    }


    /**
     * 微信退款
     *
     * @return
     * @throws Exception
     */
    @GetMapping("/refund")
    public AjaxResult refund(@RequestParam("orderId") Long orderId, @RequestParam("money") Integer money) throws Exception {
        ShopOrder shopOrder = orderService.getById(orderId);
        if (shopOrder.getOrderStatus() == 4) {
            return AjaxResult.success("订单已退款成功");
        }
//		//1 微信 2 支付宝
//		if ("2".equals(shopOrder.getPayType())) {
//			return alipayRefund(orderId.toString(), shopOrder.getTransactionId(), new BigDecimal(money));
//		} else {
        return wxReturn(orderId, money, shopOrder);
//		}
    }

    /**
     * 微信回调接口
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @PostMapping("/back")
    public String wxPayCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("+++++++++++++++++++++++++++++++++++++开始支付回调+++++++++++++++++++++++++++++++++++++++++++++++++");
        System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
        String readData = readData(request);

        NotificationRequest notificationRequest = new NotificationRequest.Builder()
                .withSerialNumber(request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_SERIAL))
                .withNonce(request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_NONCE))
                .withTimestamp(request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_TIMESTAMP))
                .withSignature(request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_SIGNATURE))
                .withBody(readData)
                .build();


        NotificationHandler handler = new NotificationHandler(
                wxpayConfigService.getVerifier(), apiKey3.getBytes(StandardCharsets.UTF_8));
        // 验签和解析请求体
        Notification notification = null;
        try {
            notification = handler.parse(notificationRequest);
        } catch (ValidationException e) {
            throw new RuntimeException(e);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }


        log.info("====================验签和解析请求体=================>>{}", notification.toString());
        AesUtil util = new AesUtil(apiKey3.getBytes(StandardCharsets.UTF_8));
        Notification.Resource resource = notification.getResource();
        String ciphertext = resource.getCiphertext();
        log.info("===密文==={}", ciphertext);
        String associatedData = resource.getAssociatedData();
        String nonce = resource.getNonce();
        String plainText = null;
        try {
            plainText = util.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
        log.info("===明文==={}", plainText);
        com.alibaba.fastjson2.JSONObject jsonObject = com.alibaba.fastjson2.JSONObject.parseObject(plainText);


        String trade_state = jsonObject.get("trade_state").toString();
        //String trade_state_desc = jsonObject.get("trade_state_desc").toString();
        if (trade_state.equals("SUCCESS")) {
            //支付成功操作
            //订单编号
            String out_trade_no = jsonObject.get("out_trade_no").toString();
            String orderId = out_trade_no.replace("wx_bank_card_", "");
            String transaction_id = jsonObject.get("transaction_id").toString();
            //获取金额
            String amount = jsonObject.get("amount").toString();
            com.alibaba.fastjson2.JSONObject amountJson = com.alibaba.fastjson2.JSONObject.parseObject(amount);
            String total = amountJson.get("total").toString();
            String bankType = jsonObject.getString("bank_type");

            ShopOrder shopOrder = orderService.getById(orderId);
            if(shopOrder.getPayStatus()==1l){
                //设置状态码
                response.setStatus(200);
                return "{"+
                        '"'+ "code"+'"'+":"+'"'+"SUCCESS"+'"'+" "+
                        '"'+ "message"+'"'+":"+'"'+"成功"+'"'+
                        "}";
            }

            if (shopOrder != null) {
                shopOrder.setPayStatus(1l);
                shopOrder.setTransactionId(transaction_id);
                shopOrder.setPayType("1");
                shopOrder.setOrderAmount(new BigDecimal(total).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP));
                //中信信用卡支付发放发放放卡卷
                if (bankType.equals("CITIC_CREDIT")) {
                    log.info("++++++++++++++++++++++++++++++++++开始发放卡卷+++++++++++++++++++++++++++++++++++++++");
                    asyncService.sendCard(shopOrder.getOpenid(), shopOrder.getOrderId());
                } else {
                    //非中信信用卡 退款
                    log.info("++++++++++++++++++++++++++++++++++非中信信用卡,开始退款+++++++++++++++++++++++++++++++++++++++");
                    asyncService.returnMoneyPay(shopOrder, out_trade_no);
                }
                orderService.updateById(shopOrder);
            }
            //设置状态码
            response.setStatus(200);
            return "{"+
                    '"'+ "code"+'"'+":"+'"'+"SUCCESS"+'"'+" "+
                    '"'+ "message"+'"'+":"+'"'+"成功"+'"'+
                    "}";
        }else {
                    response.setStatus(500);
            return "{"+
                    '"'+ "code"+'"'+":"+'"'+"fail"+'"'+" "+
                    '"'+ "message"+'"'+":"+'"'+"失败"+'"'+
                    "}";
        }

    }

    @PostMapping("/back/returnPay")
    public String returnPay(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("+++++++++++++++++++++++++++++++++++++++微信退款回调+++++++++++++++++++++++++++++++++++++++++++++++");
        System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
        String readData = readData(request);
        NotificationRequest notificationRequest = new NotificationRequest.Builder()
                .withSerialNumber(request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_SERIAL))
                .withNonce(request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_NONCE))
                .withTimestamp(request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_TIMESTAMP))
                .withSignature(request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_SIGNATURE))
                .withBody(readData)
                .build();

        NotificationHandler handler = new NotificationHandler(
                wxpayConfigService.getVerifier(), apiKey3.getBytes(StandardCharsets.UTF_8));
        // 验签和解析请求体
        Notification notification = null;
        try {
            notification = handler.parse(notificationRequest);
        } catch (ValidationException e) {
            throw new RuntimeException(e);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }


        log.info("====================验签和解析请求体=================>>{}", notification.toString());
        AesUtil util = new AesUtil(apiKey3.getBytes(StandardCharsets.UTF_8));
        Notification.Resource resource = notification.getResource();
        String ciphertext = resource.getCiphertext();
        log.info("===密文==={}", ciphertext);
        String associatedData = resource.getAssociatedData();
        String nonce = resource.getNonce();
        String plainText = null;
        try {
            plainText = util.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
        log.info("===明文==={}", plainText);
        com.alibaba.fastjson2.JSONObject jsonObject = com.alibaba.fastjson2.JSONObject.parseObject(plainText);


        String trade_state = jsonObject.get("refund_status").toString();
        //String trade_state_desc = jsonObject.get("trade_state_desc").toString();
        if (trade_state.equals("SUCCESS")) {
            //支付成功操作
            //订单编号
            String out_trade_no = jsonObject.get("out_trade_no").toString();
            String orderId = out_trade_no.replace("wx_bank_card_", "");
            //-------------------------------------------------------------
            ShopOrder shopOrder = orderService.getById(orderId);
            if(shopOrder.getOrderStatus()==4){
                //设置状态码
                response.setStatus(200);
                return "{"+
                        '"'+ "code"+'"'+":"+'"'+"SUCCESS"+'"'+" "+
                        '"'+ "message"+'"'+":"+'"'+"成功"+'"'+
                        "}";
            }
            //处理业务逻辑
            log.info("+++++++++++++++++++++++++++++++修改订单状态++++++++++++++++++++++++++++++++++++++");
            int i = orderService.updateStatusByOrderId(orderId);
            log.info("+++++++++++++++++++++++++++++++修改订单状态数:"+i+"++++++++++++++++++++++++++++++++++++++");
            //释放库存
            //加库存
            log.info("+++++++++++++++++++++++++++++++退款完成修改订单库存++++++++++++++++++++++++++++++++++++");
            if (redisTemplate.hasKey("card_num")) {
                redisTemplate.opsForValue().increment("card_num");
                log.info(orderId+"退款完成添加库存===>{}",(int)redisTemplate.opsForValue().get("card_num"));
            }
            //设置状态码
            response.setStatus(200);
            return "{"+
                    '"'+ "code"+'"'+":"+'"'+"SUCCESS"+'"'+" "+
                    '"'+ "message"+'"'+":"+'"'+"成功"+'"'+
                    "}";

        } else {
            response.setStatus(500);
            Map<String, String> payResponse = new HashMap<>();
            payResponse.put("code", "ERROR");
            payResponse.put("message", "失败");
            return JSON.toJSONString(payResponse);
        }


    }





/*	public AjaxResult alipayRefund(String orderNo, String aliReturnPayId, BigDecimal price) {
		AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", appid
				, privateKey, "json", "UTF-8"
				, aliPublicKey, "RSA2");

		AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
		Map map = new HashMap(4);
		map.put("out_trade_no", orderNo);
		//支付宝返回交易流水号
		map.put("trade_no", aliReturnPayId);
		map.put("out_request_no", UUID.randomUUID().toString().replace("-", ""));
		//退款金额
		map.put("refund_amount", price.divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP));
		//退款原因
		map.put("refund_reason", "取消订单");
		String s = com.alibaba.fastjson.JSONObject.toJSONString(map);
		request.setBizContent(s);
		//请求支付宝，执行退款
		AlipayTradeRefundResponse response = null;
		try {
			response = alipayClient.execute(request);
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		if (response.isSuccess()) {
			log.info("支付宝退款调用成功！");
			//处理业务逻辑
			ShopOrder shopOrder = new ShopOrder();
			shopOrder.setOrderId(Long.valueOf(orderNo));
			shopOrder.setUpdateBy(SecurityUtils.getUsername());
			shopOrder.setUpdateTime(new Date());
			//改为已退款
			shopOrder.setOrderStatus(4);
			//将单位分转换为元
			BigDecimal divide = price.divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);

			shopOrder.setReturnPrice(divide);
			shopOrder.setAddTime(new Date());
			try {
				shopOrderService.updateById(shopOrder);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
			log.info("----------------更新订单成功---------------------------");
			return AjaxResult.success("退款成功");

		} else {
			log.info(response.getSubMsg());
			return AjaxResult.error(response.getSubMsg() + ",退款失败");
		}

	}*/


    private AjaxResult wxReturn(Long orderId, Integer money, ShopOrder shopOrder) throws Exception {
        // 商家内部的退款单号
        String myRefundNo = shopOrder.getTransactionId();


        WechatPayHttpClientBuilder builder = getWechatPayHttpClientBuilder();

        CloseableHttpClient httpClient = builder.build();
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds");
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode rootNode = objectMapper.createObjectNode();
        rootNode.put("out_trade_no", "shop_order_" + orderId);
        rootNode.put("out_refund_no", myRefundNo);
        rootNode.put("notify_url", domain.concat("/returnPay"));
        Integer multiply = shopOrder.getOrderAmount().multiply(new BigDecimal(100)).intValue();
        rootNode.putObject("amount")
                .put("refund", money)
                .put("total", multiply)
                .put("currency", "CNY");
        objectMapper.writeValue(bos, rootNode);

        httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
        CloseableHttpResponse response = httpClient.execute(httpPost);

        String result = EntityUtils.toString(response.getEntity());
        log.info("结果是：{}", result);
        return AjaxResult.success(com.alibaba.fastjson2.JSONObject.parseObject(result));
    }


//	private String aliPay(WxpayResponse wxpayResponse) throws Exception {
//		AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", appid, privateKey, "json", "UTF-8", aliPublicKey, "RSA2");
//		AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();// 创建API对应的request
//		alipayRequest.setNotifyUrl(notifyUrl);
//		alipayRequest.setReturnUrl("https://shop.dingkuoshiye.com/#/");
//
//		Map<String, Object> map = new HashMap<String, Object>();
//		map.put("out_trade_no", wxpayResponse.getOrderId());
//		map.put("total_amount", new BigDecimal(wxpayResponse.getAmount()).setScale(2));
//		//map.put("total_amount", 0.01);
//		map.put("subject", "臻享贵宾厅");
//		map.put("product_code", "QUICK_WAP_PAY");
//		alipayRequest.setBizContent(com.alibaba.fastjson.JSONObject.toJSONString(map));// 填充业务参数
//		String form = null; // 调用SDK生成表单
//		try {
//			AlipayTradeWapPayResponse response = alipayClient.pageExecute(alipayRequest, "post");
//			if (response.isSuccess()) {
//				System.out.println("调用成功");
//			} else {
//				System.out.println("调用失败");
//			}
//			form = response.getBody();
//
//			System.out.println("form=====================================================" + form);
//		} catch (AlipayApiException e) {
//			e.printStackTrace();
//		}
//		return form;
//
//	}

    private String wxPay(WxpayResponse wxpayResponse) throws Exception {

        WechatPayHttpClientBuilder builder = getWechatPayHttpClientBuilder();

        CloseableHttpClient httpClient = builder.build();

        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");

        // OutputStream流用来保存请求数据
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();

        // 订单失效时间(可填可不填)
        String timeExpire = CommonUtil.dateToTimeZone(System.currentTimeMillis() + 1000 * 60 * 60);
        // 随机生成订单号

        log.info("订单号是：{}", wxpayResponse.getOrderId());
        ObjectNode rootNode = objectMapper.createObjectNode();
        // 还有其他字段，例如attach 可填可不填
        rootNode.put("mchid", mchId)
                .put("appid", appId)
                .put("description", "微信卡卷")
                .put("notify_url", domain)
                .put("out_trade_no", "wx_bank_card_" + wxpayResponse.getOrderId())
                .put("time_expire", timeExpire);
        rootNode.putObject("amount").put("total", 1);
        rootNode.putObject("payer")
                .put("openid", wxpayResponse.getOpenid());

        objectMapper.writeValue(bos, rootNode);

        httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
        log.info("下单参数是：" + bos.toString("UTF-8"));

        // 发出请求得到响应结果
        CloseableHttpResponse response = httpClient.execute(httpPost);
        String result = EntityUtils.toString(response.getEntity());
        JSONObject jsonObject = JSONUtil.parseObj(result);
        log.info("打印支付返回结果===>{}",jsonObject);
        String prepayId = jsonObject.getStr("prepay_id");
        if (prepayId == null) {
            throw new Exception("支付异常");
        }
        log.info("结果是：{}", result);
        Map<String, String> map = CommonUtil.buildPayMap(appId, prepayId, keyPath);
        log.info("唤起支付参数:{}", map);
        return JSONUtil.toJsonStr(map);
    }

    private WechatPayHttpClientBuilder getWechatPayHttpClientBuilder() throws Exception {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
                new FileInputStream(keyPath));

        // 获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();

        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(mchId, new WechatPay2Credentials(mchId,
                        new PrivateKeySigner(CommonUtil.getSerialNumber(mchSerialNo, certPath), merchantPrivateKey)),
                apiKey3.getBytes(StandardCharsets.UTF_8));
        // ... 若有多个商户号，可继续调用putMerchant添加商户信息

        // 从证书管理器中获取verifier
        Verifier verifier = certificatesManager.getVerifier(mchId);
// ... 接下来，你仍然可以通过builder设置各种参数，来配置你的HttpClient

        X509Certificate certificate = verifier.getValidCertificate();
        List<X509Certificate> certificates = new ArrayList<>();
        certificates.add(certificate);

        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(mchId, CommonUtil.getSerialNumber(mchSerialNo, certPath), merchantPrivateKey)
                .withWechatPay(certificates);
        // ... 接下来，你仍然可以通过builder设置各种参数，来配置你的HttpClient

        // 通过WechatPayHttpClientBuilder构造的HttpClient，会自动的处理签名和验签
        return builder;
    }


    public static String readData(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line; (line = br.readLine()) != null; ) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 将指定的时间转换为 RFC3339 格式
     *
     * @param date 需要转换的时间对象
     * @return 转换后的 RFC3339 格式字符串
     */
    public static String toRFC3339(Date date) {
        if (date == null) {
            throw new IllegalArgumentException("Date cannot be null");
        }

        // 设置 RFC3339 格式
        SimpleDateFormat rfc3339Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
        rfc3339Format.setTimeZone(TimeZone.getTimeZone("UTC")); // 设置时区为 UTC

        return rfc3339Format.format(date);
    }


    /**
     * 生成商户单据号
     *
     * @param merchantId 商户ID
     * @return 商户单据号
     */
    public static String generateOrderNo(String merchantId) {
        // 获取当前日期，格式为 yyyyMMdd
        String date = new SimpleDateFormat("yyyyMMdd").format(new Date());

        // 生成唯一流水号，使用UUID的一部分
        String uuidPart = UUID.randomUUID().toString().replace("-", "").substring(0, 8);

        // 拼接商户单据号，格式为：商户ID + 日期 + 流水号
        return merchantId + "|" + date + "|" + uuidPart;
    }


}
